﻿Imports System.Configuration

''' <summary>
''' コンフィグリーダー
''' </summary>
''' <remarks></remarks>
Public Class MConfigReader

    Private Shared _instance As MConfigReader

    ''' <summary>
    ''' 値読み込みイベント
    ''' </summary>
    ''' <remarks>
    ''' #5 イベントを見直す
    ''' </remarks>
    Public Event OnReadValue(sender As Object, e As SettingReadEventArgs)

    ''' <summary>
    ''' 環境読み込みイベント
    ''' </summary>
    ''' <remarks>
    ''' #5 イベントを見直す
    ''' </remarks>
    Public Event OnReadEnvironment(sender As Object, e As EnvironmentReadEventArgs)

    Private Sub New()
    End Sub

    Public Shared Function Instance() As MConfigReader
        If _instance Is Nothing Then
            _instance = New MConfigReader
        End If
        Return _instance
    End Function

    ''' <summary>
    ''' 環境名を取得します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>
    ''' #3 Readerのメソッド名を統一化する
    ''' </remarks>
    Public Function ReadEnvironmentName() As String
        '#5 イベントを見直す
        'キャッシュされている場合、キャッシュ値を返す
        Static name As String = String.Empty
        If String.IsNullOrEmpty(name) = False Then
            Return name
        End If

        Dim exe = Handler.Execution
        Dim e As New EnvironmentReadEventArgs(exe.Name, exe.Tag)
        RaiseEvent OnReadEnvironment(Me, e)

        Return e.EnvironmentName
    End Function

    ''' <summary>
    ''' 環境を取得します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>
    ''' #3 Readerのメソッド名を統一化する
    ''' </remarks>
    Public Function ReadEnvironment() As EnvironmentElement
        Dim name As String = Me.ReadEnvironmentName()
        Return Handler.Environments.GetElement(name)
    End Function

    ''' <summary>
    ''' 設定値を取得します
    ''' </summary>
    ''' <param name="name">設定名</param>
    ''' <remarks>
    ''' #2 値取得のメソッド名を変える
    ''' </remarks>
    Public Function ReadValue(name As String) As String
        Dim env As EnvironmentElement = Me.ReadEnvironment()
        Dim ele As SettingElemnt = env.settings.GetElement(name)
#If DEBUG Then
        If ele Is Nothing Then
            Throw New InvalidSettingNameException(name)
        End If
#End If
        Dim val As String = ele.Value

        Dim e As New SettingReadEventArgs(env.Name, name, ele.Value, ele.Tag)
        RaiseEvent OnReadValue(Me, e)

        Return e.Value
    End Function

    ''' <summary>
    ''' アプリケーション構成ファイルからSystemConfigSectionHandlerを生成します
    ''' </summary>
    Private Shared Function Handler() As MConfigSectionHandler
        Static h As MConfigSectionHandler = Nothing
        If h IsNot Nothing Then Return h

        '#7 アプリケーション構成ファイル名をMConfig.configにする
        Dim file As String = "MConfig.config"
        Dim exe As String = Environment.GetCommandLineArgs(0)
        Dim fullpath As String = IO.Path.Combine(IO.Path.GetDirectoryName(exe), file)

        If IO.File.Exists(fullpath) = False Then
            Dim msg As String = String.Format("ファイルが見つかりません。(name:{0})", file)
            Throw New ConfigFileException(msg)
        End If

        Dim map As New ExeConfigurationFileMap With {.ExeConfigFilename = file}
        Dim config As Configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None)

        Dim name As String = "mconfig"
        Dim sec As ConfigurationSection = DirectCast(config.GetSection(name), ConfigurationSection)
        If sec Is Nothing Then
            Dim msg As String = String.Format("アプリケーション構成ファイルのセクション取得に失敗しました。(name:{0})", name)
            Throw New ConfigFileException(msg)
        End If
        h = DirectCast(sec, MConfigSectionHandler)

        Return h
    End Function

End Class
